home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / game / wins1726.zip / ENCODER.C < prev    next >
C/C++ Source or Header  |  1992-02-27  |  26KB  |  788 lines

  1. /*
  2.     encoder.c - GIF Encoder and associated routines
  3.     This module is linked as an overlay, use ENTER_OVLY and EXIT_OVLY.
  4. */
  5.  
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include "fractint.h"
  10. #include "fractype.h"
  11.  
  12. /* MCP 10-27-91 */
  13. #ifdef WINFRACT
  14.    extern int OperCancelled;
  15.    void OpenStatusBox(void);
  16.    void UpdateStatusBox(unsigned long Partial, unsigned long Total);
  17.    void CloseStatusBox(void);
  18. #endif
  19.  
  20. /* routines in this module    */
  21.  
  22. void encoder_overlay(void);
  23. int  savetodisk(char *);
  24. int  encoder(void);
  25.  
  26. extern char s_cantopen[];
  27. extern char s_cantwrite[];
  28. extern char s_cantcreate[];
  29. extern char s_cantunderstand[];
  30. extern char s_cantfind[];
  31.  
  32. static void _fastcall setup_save_info(struct fractal_info *);
  33. static int inittable(void);
  34. static int _fastcall shftwrite(unsigned char *color,int numcolors);
  35. static int _fastcall raster(unsigned int);
  36. static int  _fastcall extend_blk_len(int datalen);
  37. static int _fastcall put_extend_blk(int block_id,int block_len,char far *block_data);
  38. static int  _fastcall store_item_name(char *);
  39.  
  40. extern int initbatch;
  41. extern char far *resume_info;        /* pointer to resume info if allocated */
  42. extern int  resume_len;         /* length of resume info */
  43. extern char LName[];
  44. extern char FormName[];         /* formula name */
  45. extern char IFSName[];
  46. extern int  active_system;        /* 0=dos, 1=windows */
  47. extern int  far *ranges;
  48. extern int  rangeslen;
  49.  
  50. extern    int    sxdots,sydots;        /* # of dots on the physical screen    */
  51. extern    int    sxoffs,syoffs;        /* physical top left of logical screen */
  52. extern    int    xdots, ydots;        /* # of dots on the logical screen     */
  53. extern    int    viewwindow;        /* 0 for full screen, 1 for window */
  54. extern    float    finalaspectratio;    /* for view shape and rotation */
  55. extern    int    viewxdots,viewydots;    /* explicit view sizing */
  56. extern    int    colors;         /* maximum colors available */
  57. extern    int    dotmode;        /* so we can detect disk-video */
  58. extern    char overwrite;         /* overwrite on/off */
  59. extern    int    resave_flag;        /* resaving after a timed save */
  60. extern    int    started_resaves;
  61. extern    int    timedsave;        /* if doing an auto save */
  62. extern    int    disk16bit;        /* 16 bit continuous potential */
  63.  
  64. extern unsigned char dacbox[256][3];    /* Video-DAC (filled in by SETVIDEO) */
  65. extern    int    gotrealdac;        /* DAC valid? */
  66. extern int    daclearn, daccount;    /* used by the color-cyclers */
  67. extern int    extraseg;        /* used by Save-to-GIF routines */
  68. extern int    debugflag;
  69.  
  70. extern int    gif87a_flag;        /* if 1, supress GIF extension blocks */
  71.  
  72. extern int    calc_status;
  73. extern long   calctime;
  74. extern char   stdcalcmode;
  75. extern int    fractype;
  76. extern double xxmin,xxmax;
  77. extern double yymin,yymax;
  78. extern double xx3rd,yy3rd;
  79. extern double param[4];
  80. extern int    maxit;            /* try this many iterations */
  81. extern int    fillcolor;        /* fill color: -1 = normal  */
  82. extern int    inside;            /* inside color: 1=blue     */
  83. extern int    outside;            /* outside color, if set    */
  84. extern int    finattract;        /* finite attractor option  */
  85. extern int    forcesymmetry;
  86. extern int    LogFlag;            /* non-zero if logarithmic palettes */
  87. extern int    rflag, rseed;
  88. extern int    periodicitycheck;
  89. extern char   useinitorbit;
  90. extern struct complex initorbit;
  91. extern int    pot16bit;
  92. extern float  finalaspectratio;
  93. extern double potparam[3];        /* three potential parameters*/
  94. extern double inversion[];
  95. extern int    decomp[];
  96. extern int    distest;            /* non-zero if distance estimator   */
  97. extern int    distestwidth;
  98. extern int    init3d[20];        /* '3d=nn/nn/nn/...' values */
  99. extern char   floatflag;        /* floating-point fractals? */
  100. extern int    usr_biomorph;
  101. extern int    bailout;            /* user input bailout value */
  102. extern int    previewfactor;
  103. extern int    xtrans;
  104. extern int    ytrans;
  105. extern int    red_crop_left;
  106. extern int    red_crop_right;
  107. extern int    blue_crop_left;
  108. extern int    blue_crop_right;
  109. extern int    red_bright;
  110. extern int    blue_bright;
  111. extern int    xadjust;
  112. extern int    eyeseparation;
  113. extern int    glassestype;
  114. extern int    save_system;
  115. extern int    save_release;
  116. extern int    display3d;        /* 3D display flag: 0 = OFF */
  117. extern int    Ambient;
  118. extern int    RANDOMIZE;
  119. extern int    haze;
  120. extern int    transparent[2];
  121. extern int    rotate_lo,rotate_hi;
  122. extern char   busy;
  123.  
  124. extern int    timer(int timertype,int(*subrtn)(),...);
  125.  
  126. /*
  127.             Save-To-Disk Routines (GIF)
  128.  
  129. GIF and 'Graphics Interchange Format' are trademarks (tm) of Compuserve
  130. Incorporated, an H&R Block Company.
  131.  
  132.  
  133. The following routines perform the GIF encoding when the 's' key is pressed.
  134. The routines refer to several variables that are declared elsewhere
  135. [colors, xdots, ydots, and 'dacbox'], and rely on external routines to
  136. actually read and write screen pixels [getcolor(x,y) and putcolor(x,y,color)].
  137. (Writing pixels is just stuffed in here as a sort of visual status report,
  138. and has nothing to do with any GIF function.)    They also rely on the
  139. existence of an externally-defined 64K dataspace and they use the routines
  140. 'toextra()' and 'cmpextra()' to deal with that dataspace (in the same manner
  141. as 'memcpy()' and 'memcmp()' would).   Otherwise, they perform a generic
  142. GIF-encoder function.
  143.  
  144. Note that these routines use small string- and hash-tables, and "flush"
  145. the GIF entries whenever the hash-table gets two-thirds full or the string
  146. table gets full.   They also use the GIF encoding technique of limiting the
  147. encoded string length to a specific size, "adding" a string to the hash table
  148. at that point even if a matching string exists ("adding" is in quotes, because
  149. if a matching string exists we can increment the code counter but safely throw
  150. the duplicate string away, saving both string space and a hash table entry).
  151.  
  152.    This results in relatively good speed and small data space, but at the
  153. expense of compression efficiency (filesize).    These trade-offs could be
  154. adjusted by modifying the #DEFINEd variables below.
  155.  
  156. Note that the 'strlocn' and 'teststring' routines are declared
  157. to be external just so that they can be defined (and the space re-used)
  158. elsewhere.  The actual declarations are in the assembler code.
  159.  
  160. */
  161.  
  162. #define MAXTEST   100        /* maximum single string length */
  163. #define MAXSTRING 64000     /* total space reserved for strings */
  164.                 /* maximum number of strings available */
  165. #define MAXENTRY  5003        /* (a prime number is best for hashing) */
  166.  
  167. extern unsigned int strlocn[MAXENTRY];
  168. extern unsigned char teststring[MAXTEST];
  169. extern unsigned char block[266];   /* GIF-encoded blocks go here */
  170.  
  171. static int numsaves = 0;    /* For adjusting 'save-to-disk' filenames */
  172.  
  173. static FILE *out;
  174. static int last_colorbar;
  175. static int save16bit;
  176. static int outcolor1s, outcolor2s;
  177.  
  178. static int lentest, lastentry, numentries, numrealentries;
  179. static unsigned int nextentry;
  180. static int clearcode, endcode;
  181. static unsigned int hashcode;
  182.  
  183. static unsigned char blockcount;
  184. static int startbits, codebits, bytecount, bitcount;
  185.  
  186. static char paletteBW[] = {            /* B&W palette */
  187.       0,  0,  0, 63, 63, 63,
  188.     };
  189. static char paletteCGA[] = {            /* 4-color (CGA) palette  */
  190.       0,  0,  0, 21, 63, 63, 63, 21, 63, 63, 63, 63,
  191.     };
  192. static char paletteEGA[] = {            /* 16-color (EGA/CGA) pal */
  193.       0,  0,  0,  0,  0, 42,  0, 42,  0,  0, 42, 42,
  194.      42,  0,  0, 42,  0, 42, 42, 21,  0, 42, 42, 42,
  195.      21, 21, 21, 21, 21, 63, 21, 63, 21, 21, 63, 63,
  196.      63, 21, 21, 63, 21, 63, 63, 63, 21, 63, 63, 63,
  197.     };
  198.  
  199. void encoder_overlay() { }    /* for restore_active_ovly */
  200.  
  201. int savetodisk(filename)    /* save-to-disk routine */
  202. char *filename;
  203. {
  204. char tmpmsg[41]; /* before openfile in case of overrun */
  205. char openfile[80], openfiletype[10];
  206. char tmpfile[80];
  207. int newfile;
  208. int i, j, outcolor1, outcolor2, interrupted;
  209.  
  210. ENTER_OVLY(OVLY_ENCODER);
  211.  
  212. restart:
  213.  
  214. save16bit = disk16bit;
  215. if (gif87a_flag) /* not storing non-standard fractal info */
  216.     save16bit = 0;
  217.  
  218. strcpy(openfile,filename);        /* decode and open the filename */
  219. strcpy(openfiletype,DEFAULTFRACTALTYPE);/* determine the file extension */
  220. if (save16bit)
  221.     strcpy(openfiletype,".pot");
  222. for (i = 0; i < strlen(openfile); i++)
  223.     if (openfile[i] == '.') {
  224.         strcpy(openfiletype,&openfile[i]);
  225.         openfile[i] = 0;
  226.         }
  227. if (resave_flag != 1)
  228.     updatesavename(filename); /* for next time */
  229.  
  230. strcat(openfile,openfiletype);
  231.  
  232. strcpy(tmpfile,openfile);
  233. if (access(openfile,0) != 0) /* file doesn't exist */
  234.     newfile = 1;
  235. else { /* file already exists */
  236.     if (overwrite == 0) {
  237.         if (resave_flag == 0)
  238.             goto restart;
  239.         if (started_resaves == 0) { /* first save of a savetime set */
  240.             updatesavename(filename);
  241.             goto restart;
  242.             }
  243.         }
  244.     if (access(openfile,2) != 0) {
  245.         sprintf(tmpmsg,s_cantwrite,openfile);
  246.         stopmsg(0,tmpmsg);
  247.         EXIT_OVLY;
  248.         return -1;
  249.         }
  250.     newfile = 0;
  251.     i = strlen(tmpfile);
  252.     while (--i >= 0 && tmpfile[i] != '\\')
  253.         tmpfile[i] = 0;
  254.     strcat(tmpfile,"fractint.tmp");
  255.     }
  256. started_resaves = (resave_flag == 1) ? 1 : 0;
  257. if (resave_flag == 2) /* final save of savetime set? */
  258.     resave_flag = 0;
  259. if ((out=fopen(tmpfile,"wb")) == NULL) {
  260.     sprintf(tmpmsg,s_cantcreate,tmpfile);
  261.     stopmsg(0,tmpmsg);
  262.     EXIT_OVLY;
  263.     return -1;
  264.     }
  265.  
  266. if (dotmode == 11) {            /* disk-video */
  267.     char buf[60];
  268.     sprintf(buf,"Saving %s",openfile);
  269.     dvid_status(1,buf);
  270.     }
  271.  
  272. busy = 1;
  273. if (debugflag != 200)
  274.     interrupted = encoder();
  275. else
  276.     interrupted = timer(2,NULL);    /* invoke encoder() via timer */
  277. busy = 0;
  278.  
  279. fclose(out);
  280.  
  281. if (interrupted) {
  282.     char buf[200];
  283.     sprintf(buf,"Save of %s interrupted.\nCancel to ",openfile);
  284.     if (newfile)
  285.         strcat(buf,"delete the file,\ncontinue to keep the partial image.");
  286.     else
  287.         strcat(buf,"retain the original file,\ncontinue to replace original with new partial image.");
  288.     interrupted = 1;
  289.     if (stopmsg(2,buf) < 0) {
  290.         interrupted = -1;
  291.         unlink(tmpfile);
  292.         }
  293.     }
  294.  
  295. if (newfile == 0 && interrupted >= 0) { /* replace the real file */
  296.     unlink(openfile);        /* success assumed since we checked */
  297.     rename(tmpfile,openfile);    /* earlier with access            */
  298.     }
  299.  
  300. if (dotmode != 11) {            /* supress this on disk-video */
  301.     if (active_system == 0) {        /* no bars in Windows version */
  302.     outcolor1 = outcolor1s;
  303.     outcolor2 = outcolor2s;
  304.     for (j = 0; j <= last_colorbar; j++) {
  305.         if ((j & 4) == 0) {
  306.             if (++outcolor1 >= colors) outcolor1 = 0;
  307.             if (++outcolor2 >= colors) outcolor2 = 0;
  308.             }
  309.         for (i = 0; 250*i < xdots; i++) { /* clear vert status bars */
  310.             putcolor(i,j,getcolor(i,j)^outcolor1);
  311.             putcolor(xdots-1-i,j,getcolor(xdots-1-i,j)^outcolor2);
  312.             }
  313.         }
  314.     }
  315.     }
  316. else                    /* disk-video */
  317.     dvid_status(1,"");
  318. if (interrupted) {
  319.     texttempmsg(" *interrupted* save ");
  320.     EXIT_OVLY;
  321.     return -1;
  322.     }
  323. if (timedsave == 0) {
  324.     buzzer(0);
  325.     if (initbatch == 0) {
  326.         sprintf(tmpmsg," File saved as %s ",openfile);
  327.         texttempmsg(tmpmsg);
  328.         }
  329.     }
  330. EXIT_OVLY;
  331. return 0;
  332. }
  333.  
  334.  
  335. int encoder()
  336. {
  337. int i, ydot, xdot, color, outcolor1, outcolor2;
  338. int width;
  339. int rownum, rowlimit;
  340. unsigned int hashentry;
  341. unsigned char bitsperpixel, x;
  342. int entrynum;
  343. struct fractal_info save_info;
  344.  
  345. if(initbatch)            /* flush any impending keystrokes */
  346.    while(keypressed())
  347.       getakey();
  348.  
  349. setup_save_info(&save_info);
  350.  
  351. bitsperpixel = 0;            /* calculate bits / pixel */
  352. for (i = colors; i >= 2; i /= 2 )
  353.     bitsperpixel++;
  354.  
  355. startbits = bitsperpixel+1;        /* start coding with this many bits */
  356. if (colors == 2)
  357.     startbits++;            /* B&W Klooge */
  358.  
  359. clearcode = 1 << (startbits - 1);    /* set clear and end codes */
  360. endcode = clearcode+1;
  361.  
  362. outcolor1 = 0;                /* use these colors to show progress */
  363. outcolor2 = 1;                /* (this has nothing to do with GIF) */
  364. if (colors > 2) {
  365.     outcolor1 = 2;
  366.     outcolor2 = 3;
  367.     }
  368. if (((++numsaves) & 1) == 0) {            /* reverse the colors on alt saves */
  369.     i = outcolor1;
  370.     outcolor1 = outcolor2;
  371.     outcolor2 = i;
  372.     }
  373. outcolor1s = outcolor1;
  374. outcolor2s = outcolor2;
  375.  
  376. if (gif87a_flag == 1) {
  377.     if (fwrite("GIF87a",6,1,out) != 1) goto oops;  /* old GIF Signature */
  378. } else {
  379.     if (fwrite("GIF89a",6,1,out) != 1) goto oops;  /* new GIF Signature */
  380. }
  381.  
  382. width = xdots;
  383. rowlimit = ydots;
  384. if (save16bit) {
  385.     /* pot16bit info is stored as:
  386.        file:    double width rows, right side of row is low 8 bits
  387.        diskvid: ydots rows of colors followed by ydots rows of low 8 bits
  388.        decoder: returns (row of color info then row of low 8 bits) * ydots
  389.        */
  390.     rowlimit <<= 1;
  391.     width <<= 1;
  392.     }
  393. if (fwrite(&width,2,1,out) != 1) goto oops;  /* screen descriptor */
  394. if (fwrite(&ydots,2,1,out) != 1) goto oops;
  395. x = 128 + ((6-1)<<4) + (bitsperpixel-1); /* color resolution == 6 bits worth */
  396. if (fwrite(&x,1,1,out) != 1) goto oops;
  397. if (fputc(0,out) != 0) goto oops;    /* background color */
  398. i = 0;
  399. /** PB, changed to always store pixel aspect ratio, some utilities
  400.     have been reported to like it **/
  401. /**
  402. if ( finalaspectratio < SCREENASPECT-0.01
  403.   || finalaspectratio > SCREENASPECT+0.01) {
  404.  **/
  405. if (viewwindow                    /* less than full screen?  */
  406.   && (viewxdots == 0 || viewydots == 0))    /* and we picked the dots? */
  407.    i = ((double)sydots / (double)sxdots) * 64.0/SCREENASPECT - 14.5;
  408. else /* must risk loss of precision if numbers low */
  409.    i = (((double)ydots / (double)xdots) / finalaspectratio) * 64 - 14.5;
  410. if (i < 1)   i = 1;
  411. if (i > 255) i = 255;
  412. if (gif87a_flag) i = 0;    /* for some decoders which can't handle aspect */
  413. if (fputc(i,out) != i) goto oops;    /* pixel aspect ratio */
  414.  
  415. if (colors == 256) {            /* write out the 256-color palette */
  416.     if (gotrealdac) {         /* got a DAC - must be a VGA */
  417.         if (!shftwrite((unsigned char *)dacbox,colors)) goto oops;
  418.      } else {            /* uh oh - better fake it */
  419.         for (i = 0; i < 256; i += 16)
  420.             if (!shftwrite(paletteEGA,16)) goto oops;
  421.         }
  422.     }
  423. if (colors == 2) {            /* write out the B&W palette */
  424.     if (!shftwrite(paletteBW,colors)) goto oops;
  425.     }
  426. if (colors == 4) {            /* write out the CGA palette */
  427.     if (!shftwrite(paletteCGA,colors))goto oops;
  428.     }
  429. if (colors == 16) {            /* Either EGA or VGA */
  430.     if (gotrealdac) {
  431.         if (!shftwrite((unsigned char *)dacbox,colors))goto oops;
  432.         }
  433.      else    {            /* no DAC - must be an EGA */
  434.         if (!shftwrite(paletteEGA,colors))goto oops;
  435.         }
  436.     }
  437.  
  438. if (fwrite(",",1,1,out) != 1) goto oops;  /* Image Descriptor */
  439. i = 0;
  440. if (fwrite(&i,2,1,out) != 1) goto oops;
  441. if (fwrite(&i,2,1,out) != 1) goto oops;
  442. if (fwrite(&width,2,1,out) != 1) goto oops;
  443. if (fwrite(&ydots,2,1,out) != 1) goto oops;
  444. if (fwrite(&i,1,1,out) != 1) goto oops;
  445.  
  446. bitsperpixel = startbits - 1;        /* raster data starts here */
  447. if (fwrite(&bitsperpixel,1,1,out) != 1) goto oops;
  448.  
  449. codebits = startbits;            /* start encoding */
  450.  
  451. if (!raster(9999)) goto oops;        /* initialize the raster routine */
  452.  
  453. if (!inittable()) goto oops;        /* initialize the LZW tables */
  454.  
  455. for ( rownum = 0; rownum < ydots; rownum++
  456. #ifdef WINFRACT
  457.       , UpdateStatusBox(rownum, ydots)
  458. #endif
  459. ) {  /* scan through the dots */
  460.     for (ydot = rownum; ydot < rowlimit; ydot += ydots) {
  461.     for (xdot = 0; xdot < xdots; xdot++) {
  462.         if (save16bit == 0 || ydot < ydots)
  463.             color = getcolor(xdot,ydot);
  464.         else
  465.             color = readdisk(xdot+sxoffs,ydot+syoffs);
  466.         teststring[0] = ++lentest;
  467.         teststring[lentest] = color;
  468.         if (lentest == 1) {        /* root entry? */
  469.             lastentry = color;
  470.             continue;
  471.             }
  472.         if (lentest == 2)        /* init   the hash code */
  473.             hashcode = 301 * (teststring[1]+1);
  474.         hashcode *= (color + lentest);    /* update the hash code */
  475.         hashentry = ++hashcode % MAXENTRY;
  476.         for( i = 0; i < MAXENTRY; i++) {
  477.             if (++hashentry >= MAXENTRY) hashentry = 0;
  478.             if (cmpextra(strlocn[hashentry]+2,
  479.                 teststring,lentest+1) == 0)
  480.                     break;
  481.             if (strlocn[hashentry] == 0) i = MAXENTRY;
  482.             }
  483.         /* found an entry and string length isn't too bad */
  484.         if (strlocn[hashentry] != 0 && lentest < MAXTEST-3) {
  485.             fromextra(strlocn[hashentry],&entrynum,2);
  486.             lastentry = entrynum;
  487.             continue;
  488.             }
  489.         if (!raster(lastentry)) goto oops;    /* write entry */
  490.         numentries++;        /* act like you added one, anyway */
  491.         if (strlocn[hashentry] == 0) {    /* add new string, if any */
  492.             entrynum = numentries+endcode;
  493.             strlocn[hashentry] = nextentry;
  494.             toextra(nextentry, &entrynum,2);
  495.             toextra(nextentry+2,
  496.                 teststring,lentest+1);
  497.             nextentry += lentest+3;
  498.             numrealentries++;
  499.             }
  500.         teststring[0] = 1;        /* reset current entry */
  501.         teststring[1] = color;
  502.         lentest = 1;
  503.         lastentry = color;
  504.  
  505.         if ((numentries+endcode) == (1<<codebits))
  506.             codebits++;         /* use longer encoding */
  507.  
  508.         if ( numentries + endcode > 4093 ||    /* out of room? */
  509.             numrealentries > (MAXENTRY*2)/3 ||
  510.             nextentry > MAXSTRING-MAXTEST-5) {
  511.             if (!raster(lastentry)) goto oops;    /* flush & restart */
  512.             if (!inittable()) goto oops;
  513.             }
  514.         }
  515.     if (dotmode != 11            /* supress this on disk-video */
  516.         && active_system == 0        /* and in Windows version     */
  517.         && ydot == rownum) {
  518.         if ((ydot & 4) == 0) {
  519.             if (++outcolor1 >= colors) outcolor1 = 0;
  520.             if (++outcolor2 >= colors) outcolor2 = 0;
  521.             }
  522.         for (i = 0; 250*i < xdots; i++) {    /* display vert status bars */
  523.                             /*   (this is NOT GIF-related)    */
  524.             /* PB Changed following code to xor color, so that
  525.                image can be restored at end and resumed
  526.                putcolor(      i,ydot,outcolor1);
  527.                putcolor(xdots-1-i,ydot,outcolor2);
  528.             */
  529.             putcolor(i,ydot,getcolor(i,ydot)^outcolor1);
  530.             putcolor(xdots-1-i,ydot,getcolor(xdots-1-i,ydot)^outcolor2);
  531.             }
  532.         last_colorbar = ydot;
  533.         }
  534. #ifdef WINFRACT
  535.         keypressed();
  536.         if (OperCancelled)
  537. #else
  538.         if (keypressed())                     /* keyboard hit - bail out */
  539. #endif
  540.         ydot = rownum = 9999;
  541.     }
  542.     }
  543.  
  544. if (!raster(lastentry)) goto oops;    /* tidy up - dump the last code */
  545.  
  546. if (!raster(endcode)) goto oops;    /* finish the map */
  547.  
  548. if (fputc(0,out) != 0) goto oops;    /* raster data ends here */
  549.  
  550. if (gif87a_flag == 0) { /* store non-standard fractal info */
  551.     /* loadfile.c has notes about extension block structure */
  552.     if (ydot >= 9999)
  553.         save_info.calc_status = 0; /* partial save is not resumable */
  554.     save_info.tot_extend_len = 0;
  555.     if (resume_info != NULL && save_info.calc_status == 2) {
  556.         /* resume info block, 002 */
  557.         save_info.tot_extend_len += extend_blk_len(resume_len);
  558.         if (!put_extend_blk(2,resume_len,resume_info))goto oops;
  559.         }
  560.     if (save_info.fractal_type == FORMULA || save_info.fractal_type == FFORMULA)
  561.         save_info.tot_extend_len += store_item_name(FormName);
  562.     if (save_info.fractal_type == LSYSTEM)
  563.         save_info.tot_extend_len += store_item_name(LName);
  564.     if (save_info.fractal_type == IFS || save_info.fractal_type == IFS3D)
  565.         save_info.tot_extend_len += store_item_name(IFSName);
  566.     if (display3d <= 0 && rangeslen) {
  567.         /* ranges block, 004 */
  568.         save_info.tot_extend_len += extend_blk_len(rangeslen*2);
  569.         if (!put_extend_blk(4,rangeslen*2,(char far *)ranges))goto oops;
  570.         }
  571.  
  572.     /* main and last block, 001 */
  573.     save_info.tot_extend_len += extend_blk_len(sizeof(save_info));
  574.     if (!put_extend_blk(1,sizeof(save_info),(char far *)&save_info))goto oops;
  575.     }
  576.  
  577. if (fwrite(";",1,1,out) != 1) goto oops;          /* GIF Terminator */
  578.  
  579. return ((ydot < 9999) ? 0 : 1);
  580.  
  581. oops:
  582.     {
  583.     fflush(out);
  584.     stopmsg(0,"Error Writing to disk (Disk full?)");
  585.     return 1;
  586.     }
  587. }
  588.  
  589. static int _fastcall shftwrite(unsigned char *color,int numcolors)
  590. /* shift IBM colors to GIF */
  591. {
  592. unsigned char thiscolor;
  593. int i,j;
  594. for (i = 0; i < numcolors; i++)
  595.     for (j = 0; j < 3; j++) {
  596.         thiscolor = color[3*i+j];
  597.         thiscolor = thiscolor << 2;
  598.         thiscolor += (thiscolor >> 6);
  599.         if (fputc(thiscolor,out) != thiscolor) return(0);
  600.         }
  601. return(1);
  602. }
  603.  
  604. static int inittable()         /* routine to init tables */
  605. {
  606. int i;
  607.  
  608. if (!raster(clearcode)) return(0);    /* signal that table is initialized */
  609.  
  610. numentries = 0;             /* initialize the table */
  611. numrealentries = 0;
  612. nextentry = 1;
  613. lentest = 0;
  614. codebits = startbits;
  615.  
  616. toextra(0,"\0",1);                      /* clear the hash entries */
  617. for (i = 0; i < MAXENTRY; i++)
  618.     strlocn[i] = 0;
  619.  
  620. return(1);
  621. }
  622.  
  623. static int _fastcall raster(code)    /* routine to block and output codes */
  624. unsigned int code;
  625. {
  626. unsigned int icode, i, j;
  627.  
  628. if (code == 9999) {            /* special start-up signal */
  629.     bytecount = 0;
  630.     bitcount = 0;
  631.     for (i = 0; i < 266; i++)
  632.         block[i] = 0;
  633.     return(1);
  634.     }
  635.  
  636. icode = code << bitcount;        /* update the bit string */
  637. block[bytecount  ] |= (icode & 255);
  638. block[bytecount+1] |= ((icode>>8) & 255);
  639. icode = (code>>8) << bitcount;
  640. block[bytecount+2] |= ((icode>>8) & 255);
  641. bitcount += codebits;
  642. while (bitcount >= 8) {         /* locate next starting point */
  643.     bitcount -= 8;
  644.     bytecount++;
  645.     }
  646.  
  647. if (bytecount > 250 || code == endcode) {    /* time to write a block */
  648.     if (code == endcode)
  649.         while (bitcount > 0) {        /* if EOF, find the real end */
  650.             bitcount -= 8;
  651.             bytecount++;
  652.             }
  653.     i = bytecount;
  654.     blockcount = i;
  655.     if (fwrite(&blockcount,1,1,out) != 1) return(0); /* write the block */
  656.     if (fwrite(block,i,1,out) != 1) return(0);
  657.     bytecount = 0;                /* now re-start the block */
  658.     for (j = 0; j < 5; j++)         /* (may have leftover bits) */
  659.         block[j] = block[j+i];
  660.     for (j = 5; j < 266; j++)
  661.         block[j] = 0;
  662.     }
  663. return(1);
  664. }
  665.  
  666.  
  667. static int _fastcall extend_blk_len(int datalen)
  668. {
  669.    return(datalen + (datalen+254)/255 + 15);
  670.    /*       data   +    1.per.block   + 14 for id + 1 for null at end  */
  671. }
  672.  
  673. static int _fastcall put_extend_blk(int block_id,int block_len,char far *block_data)
  674. {
  675.    int i,j;
  676.    char header[15];
  677.    strcpy(header,"!\377\013fractint");
  678.    sprintf(&header[11],"%03u",block_id);
  679.    if (fwrite(header,14,1,out) != 1) return(0);
  680.    i = (block_len + 254) / 255;
  681.    while (--i >= 0) {
  682.       block_len -= (j = min(block_len,255));
  683.       if (fputc(j,out) != j) return(0);
  684.       while (--j >= 0)
  685.      fputc(*(block_data++),out);
  686.       }
  687.    if (fputc(0,out) != 0) return(0);
  688.    return(1);
  689. }
  690.  
  691. static int _fastcall store_item_name(char *nameptr)
  692. {
  693.    char tmpname[40];
  694.    strcpy(tmpname,nameptr);
  695.    /* formula/lsys/ifs info block, 003 */
  696.    put_extend_blk(3,40,tmpname);
  697.    return(extend_blk_len(40));
  698. }
  699.  
  700. static void _fastcall setup_save_info(struct fractal_info *save_info)
  701. {
  702.    int i;
  703.    /* set save parameters in save structure */
  704.    strcpy(save_info->info_id, INFO_ID);
  705.    save_info->version          = 8; /* file version, independant of system */
  706.    save_info->iterations      = maxit;
  707.    save_info->fractal_type    = fractype;
  708.    save_info->xmin          = xxmin;
  709.    save_info->xmax          = xxmax;
  710.    save_info->ymin          = yymin;
  711.    save_info->ymax          = yymax;
  712.    save_info->creal          = param[0];
  713.    save_info->cimag          = param[1];
  714.    save_info->videomodeax     = videoentry.videomodeax;
  715.    save_info->videomodebx     = videoentry.videomodebx;
  716.    save_info->videomodecx     = videoentry.videomodecx;
  717.    save_info->videomodedx     = videoentry.videomodedx;
  718.    save_info->dotmode          = videoentry.dotmode % 100;
  719.    save_info->xdots          = videoentry.xdots;
  720.    save_info->ydots          = videoentry.ydots;
  721.    save_info->colors          = videoentry.colors;
  722.    save_info->parm3          = 0; /* pre version==7 fields */
  723.    save_info->parm4          = 0;
  724.    save_info->dparm3          = param[2];
  725.    save_info->dparm4          = param[3];
  726.    save_info->fillcolor          = fillcolor;
  727.    save_info->potential[0]    = potparam[0];
  728.    save_info->potential[1]    = potparam[1];
  729.    save_info->potential[2]    = potparam[2];
  730.    save_info->rflag          = rflag;
  731.    save_info->rseed          = rseed;
  732.    save_info->inside          = inside;
  733.    save_info->logmap          = LogFlag;
  734.    save_info->invert[0]       = inversion[0];
  735.    save_info->invert[1]       = inversion[1];
  736.    save_info->invert[2]       = inversion[2];
  737.    save_info->decomp[0]       = decomp[0];
  738.    save_info->biomorph          = usr_biomorph;
  739.    save_info->symmetry          = forcesymmetry;
  740.    for (i = 0; i < 16; i++)
  741.       save_info->init3d[i] = init3d[i];
  742.    save_info->previewfactor   = previewfactor;
  743.    save_info->xtrans          = xtrans;
  744.    save_info->ytrans          = ytrans;
  745.    save_info->red_crop_left   = red_crop_left;
  746.    save_info->red_crop_right  = red_crop_right;
  747.    save_info->blue_crop_left  = blue_crop_left;
  748.    save_info->blue_crop_right = blue_crop_right;
  749.    save_info->red_bright      = red_bright;
  750.    save_info->blue_bright     = blue_bright;
  751.    save_info->xadjust          = xadjust;
  752.    save_info->eyeseparation   = eyeseparation;
  753.    save_info->glassestype     = glassestype;
  754.    save_info->outside          = outside;
  755.    save_info->x3rd          = xx3rd;
  756.    save_info->y3rd          = yy3rd;
  757.    save_info->calc_status     = calc_status;
  758.    save_info->stdcalcmode     = stdcalcmode;
  759.    save_info->distest          = distest;
  760.    save_info->floatflag       = floatflag;
  761.    save_info->bailout          = bailout;
  762.    save_info->calctime          = calctime;
  763.    save_info->trigndx[0]      = trigndx[0];
  764.    save_info->trigndx[1]      = trigndx[1];
  765.    save_info->trigndx[2]      = trigndx[2];
  766.    save_info->trigndx[3]      = trigndx[3];
  767.    save_info->finattract      = finattract;
  768.    save_info->initorbit[0]    = initorbit.x;
  769.    save_info->initorbit[1]    = initorbit.y;
  770.    save_info->useinitorbit    = useinitorbit;
  771.    save_info->periodicity     = periodicitycheck;
  772.    save_info->pot16bit          = disk16bit;
  773.    save_info->faspectratio    = finalaspectratio;
  774.    save_info->system          = save_system;
  775.    save_info->release          = save_release;
  776.    save_info->flag3d          = display3d;
  777.    save_info->ambient          = Ambient;
  778.    save_info->randomize       = RANDOMIZE;
  779.    save_info->haze          = haze;
  780.    save_info->transparent[0]  = transparent[0];
  781.    save_info->transparent[1]  = transparent[1];
  782.    save_info->rotate_lo       = rotate_lo;
  783.    save_info->rotate_hi       = rotate_hi;
  784.    save_info->distestwidth    = distestwidth;
  785.    for (i = 0; i < sizeof(save_info->future)/sizeof(int); i++)
  786.       save_info->future[i] = 0;
  787. }
  788.